package com.qinggeng.project.system.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.http.HttpStatus;
import com.qinggeng.common.exception.CustomException;
import com.qinggeng.framework.config.mq.MQSendUtils;
import com.qinggeng.framework.config.mq.dto.MessageAccountDTO;
import com.qinggeng.framework.config.mq.enums.MQTypeEnum;
import com.qinggeng.project.system.domain.*;
import com.qinggeng.project.system.dto.UserInvitDTO;
import com.qinggeng.project.system.mapper.SysUserMapper;
import com.qinggeng.project.system.mapper.UserAccountMapper;
import com.qinggeng.project.system.mapper.UserInvitMapper;
import com.qinggeng.project.system.service.*;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import tk.mybatis.mapper.entity.Example;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.Random;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class UserInvitServiceImpl  implements UserInvitService {
    @Resource
    private UserInvitMapper userInvitMapper;

    @Resource
    private UserInvitCodeService userInvitCodeService;

    @Resource
    private SysUserMapper sysUserMapper;

    @Resource
    private IOrdersService ordersService;

    @Autowired
    private MQSendUtils mqSendUtils;

    @Resource
    private RedissonClient  redissonClient;

    @Resource
    private UserAccountMapper userAccountMapper;

    @Resource
    private DataSourceTransactionManager dataSourceTransactionManager;

    @Resource
    private TransactionDefinition transactionDefinition;

    @Resource
    private IUserAccountService userAccountService;


    private  static  final  String PULL_NEW="PULL_NEW:";
    @Override
    public boolean checkUserInvit(Long invitUserId) {
        String key=PULL_NEW+invitUserId;
        RLock rLock = redissonClient.getLock(key);
        try {
            boolean bl=rLock.isLocked();
            if (bl){
                throw new CustomException("服务繁忙");
            }
            rLock.lock();
            UserInvit userInvit=this.getByUserInvitByUserId(invitUserId);
            if (null !=userInvit) {
                throw new CustomException("已被拉新过");
            }
        }finally {
            if (rLock.isHeldByCurrentThread()){
                rLock.unlock();
            }
        }
        return true;
    }

    @Override
    public boolean checkUserInvitCodeCreateTime(UserInvitCode userInvitCode,UserInvitDTO dto) {

      //邀请者id
        Long invitUserId=userInvitCode.getUserId();
        //用户id
        Long userId=dto.getUserId();
        if (invitUserId.equals(userId) ){
            throw new CustomException("不能邀请自己");
        }
        log.info("邀請码拥有者 {}",invitUserId);
        log.info("userId {}",userId);
        //当前用户的拉新码创建时间 需要晚与 用户的创建时间
        Long createCodeTime=userInvitCode.getInvitTimeStamp();
        Long userCreateTime=getUserCreateTime(userId);
        log.info("code創建時間 {}",createCodeTime);
        log.info("用戶創建時間 {}",userCreateTime);
        if (createCodeTime>=userCreateTime){
            throw new CustomException("您已经是果舒达老用户啦");
        }
        return true;
    }

    @Override
    public boolean checkUserInvitCoddPlaceAnOrder(Long userId) {
        boolean bl=ordersService.checkPlaceAnOrder(userId);
       if (bl){
            throw new CustomException("您已经是果舒达老用户啦");
        }
        return true;
    }

    @Override
    public UserInvit insertUserInvit(UserInvitDTO dto) {
        Long userId=dto.getUserId();

        //验证拉新活动开启
        userInvitCodeService.checkInvitActivity();

        //验证code是不是有效
        String code=dto.getCode();
        UserInvitCode userInvitCode= userInvitCodeService.checkInvitCode(code);
        //邀请者id
        Long invitUserId=userInvitCode.getUserId();
        //用户id
        //验证是不是已经拉新过
        checkUserInvit(userId);
        checkUserInvitCodeCreateTime(userInvitCode,dto);
        checkUserInvitCoddPlaceAnOrder(userId);
        //插入数据
        UserInvit userInvit=new UserInvit();
        userInvit.setCreateTime(new Date());
        userInvit.setUpdateTime(new Date());
        userInvit.setUserId(invitUserId);
        userInvit.setInvitUserId(userId);
        userInvit.setInvitTime(new Date());
        userInvit.setInvitCode(code);
        userInvit.setInvitTimeStamp(new Date().getTime());
        Long amount=Long.valueOf(new Random().nextInt(2))+3;
        userInvit.setRewardAmount(amount);

        //验证账户
        userAccountService.checkFilterUserAccount(userId);

        String lockKey= UserAccountServiceImpl.USER_ACCOUNT+userId;
        RLock lock=redissonClient.getLock(lockKey);
        if (lock.isLocked()){
            throw  new CustomException("已经提交请稍后");
        }
        lock.lock(5,TimeUnit.SECONDS);
        TransactionStatus transactionStatus=dataSourceTransactionManager.getTransaction(transactionDefinition);
        try {
            userInvitMapper.insertSelective(userInvit);
            UserAccount userAccount=new UserAccount();
            userAccount.setUserId(invitUserId);
            userAccount.setAccount(new BigDecimal(amount));
            userAccountMapper.addUserAccountMoney(userAccount);
            dataSourceTransactionManager.commit(transactionStatus);
        }catch (Exception e){
            dataSourceTransactionManager.rollback(transactionStatus);
            throw new CustomException("拉新活动异常,请稍后再试");
        }
        //发送消息
        MessageAccountDTO messageModel=new MessageAccountDTO();
        messageModel.setType(MQTypeEnum.PULL_NEW_ACCOUNT.getType());
        messageModel.setMoney(new BigDecimal(amount).toString());
        messageModel.setUserId(invitUserId);
        mqSendUtils.sendAsynMessage(messageModel);
        return userInvit;
    }


    @Override
    public UserInvit getByUserInvitByUserId(Long invitUserId) {
        Example example =new Example(UserInvit.class);
        example.createCriteria()
                .andEqualTo("invitUserId",invitUserId);
        UserInvit userInvit=userInvitMapper.selectOneByExample(example);
        return userInvit;
    }

    private  Long getUserCreateTime(Long userId){
      SysUser sysUser= sysUserMapper.selectUserById(userId);
      Date date= sysUser.getCreateTime();
      if (null==date){
          throw new CustomException("邀请者创建时间错误");
      }
      Long second=date.getTime();
      return  Long.valueOf(second);
    }
}
